home *** CD-ROM | disk | FTP | other *** search
- #include "config.h"
-
- #include <types.h>
- #include <events.h>
- #define TELOPTS
- #include <sys/time.h>
- #include <sys/ioctl.h>
- #include <sys/types.h>
- #include <arpa/telnet.h>
- #include <netdb.h>
- #include <stdio.h>
- #include <errno.h>
- #include <string.h>
- #include <ctype.h>
- #include <signal.h>
- #include <memory.h>
- #include <fcntl.h>
- #include <setjmp.h>
- #include "lint.h"
- #include "interpret.h"
- #include "comm.h"
- #include "object.h"
- #include "sent.h"
- #include "patchlevel.h"
- #include "wiz_list.h"
- #include "rc.h"
-
- void set_prompt(char *);
- char *query_ip_number(struct object *);
- static void add_ip_entry(long, char *);
-
- extern char *xalloc(), *string_copy(), *unshared_str_copy();
- extern int d_flag;
- extern int current_time;
- char * first_cmd_in_buf(struct interactive *);
- void next_cmd_in_buf(struct interactive *);
- char * skip_eols(struct interactive *, char *);
- void remove_flush_entry(struct interactive *ip);
-
- void telnet_neg(char *, char *);
- void remove_interactive(), add_ref();
-
- extern void debug_message(), fatal(), free_sentence();
-
- struct interactive **all_players;
-
- extern int errno;
-
- void new_player();
-
- void flush_all_player_mess();
-
- extern long DoGetWindow(struct interactive *ip);
- extern void DoDisposeWindow(long theWindow);
- extern void LPEvents(void);
- extern int DoWindowRead(struct interactive *ip);
- extern int DoWindowWrite(struct interactive *ip,
- const char *buf, unsigned long nbyte);
- extern Boolean gSocketActive;
-
- int num_player;
-
- int nfds;
- fd_set readfds;
-
- #define StartCmdGiver (MAX_PLAYERS-1) /* the one after heartbeat */
- #define IncCmdGiver NextCmdGiver = (NextCmdGiver < 0? StartCmdGiver: \
- NextCmdGiver - 1)
-
- int NextCmdGiver;
- int CmdsGiven; /* -1 is used to poll heart beat. */
- int twait; /* wait time for select() */
- extern int time_to_call_heart_beat, comm_time_to_call_heart_beat;
-
- #ifdef ACCESS_RESTRICTED
- extern void *allow_host_access ();
- extern void release_host_access ();
- #endif
-
- static struct object *first_player_for_flush=(struct object *)NULL;
-
- /*
- * Interprocess communication interface to the backend.
- */
-
- static int s;
- extern int port_number;
-
- void PollEvents() {
- extern short __spin_abort;
-
- gSocketActive = true;
- LPEvents();
- gSocketActive = false;
- }
-
- void prepare_ipc() {
- int tmp;
- char *host_ip;
- struct sockaddr_in sin;
-
- if (MULTI_CONNECTION) {
- s_spinroutine((ProcPtr)PollEvents);
- host_ip = inet_ntoa(xIPAddr());
- memset((char *)&sin, '\0', sizeof sin);
- memcpy((char *)&sin.sin_addr, host_ip, strlen(host_ip));
- sin.sin_port = htons((u_short)port_number);
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- s = s_socket(AF_INET, SOCK_STREAM, 0);
-
- if (s == -1) {
- perror("socket");
- LPExit(1);
- }
- tmp = 1;
- if (s_bind(s, (struct sockaddr *)&sin, sizeof sin) == -1) {
- if (errno == EADDRINUSE) {
- fprintf(stderr, "Socket already bound!\n");
- debug_message("Socket already bound!\n");
- LPExit(errno);
- } else {
- perror("bind");
- LPExit(1);
- }
- }
- if (s_listen(s, 5) == -1) {
- perror("listen");
- LPExit(1);
- }
- tmp = 1;
- if (s_ioctl(s, FIONBIO, &tmp) == -1) {
- perror("ioctl socket FIONBIO");
- LPExit(1);
- }
- }
- start_timer(2);
- twait = 0;
- CmdsGiven = 0;
- time_to_call_heart_beat = 0;
- comm_time_to_call_heart_beat = 0;
- NextCmdGiver = StartCmdGiver;
- }
-
- /*
- * This one is called when shutting down the MUD.
- */
- void ipc_remove() {
- if (MULTI_CONNECTION) {
- s_close(s);
- }
- }
-
- /*
- * Send a message to a player. If that player is shadowed, special
- * care has to be taken.
- */
- /*VARARGS1*/
- void add_message(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
- char *fmt;
- int a1, a2, a3, a4, a5, a6, a7, a8, a9;
- {
- int from, to;
- int min_length;
- char buff[10000];
- int n, chunk, length;
- int old_message_length;
- struct interactive *ip;
- char buff2[MAX_SOCKET_PACKET_SIZE+1];
-
- if (command_giver == 0 || (command_giver->flags & O_DESTRUCTED) ||
- command_giver->interactive == 0 ||
- command_giver->interactive->do_close)
- {
- #if 0
- putchar(']');
- if ( fmt != MESSAGE_FLUSH )
- printf(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
- fflush(stdout);
- #endif
- return;
- }
- ip = command_giver->interactive;
- old_message_length = ip->message_length;
- if ( fmt == MESSAGE_FLUSH ) {
- min_length = 1;
- strncpy ( buff, ip->message_buf, length=old_message_length );
- buff[length] = '\0';
- } else {
- min_length = DESIRED_SOCKET_PACKET_SIZE;
- (void)sprintf(buff+old_message_length,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9);
- length = old_message_length + strlen(buff+old_message_length);
- /*
- * Always check that your arrays are big enough ! :-)
- */
- if (length > sizeof buff)
- fatal("To long message!\n");
- if (shadow_catch_message(command_giver, buff+old_message_length))
- return;
- if (ip->snoop_by) {
- struct object *save = command_giver;
- command_giver = ip->snoop_by->ob;
- add_message("%%%s", buff+old_message_length);
- command_giver = save;
- }
- if ( length >= min_length ) {
- strncpy ( buff, ip->message_buf, old_message_length );
- } else {
- strcpy( ip->message_buf+old_message_length,
- buff+old_message_length );
- }
- }
- if (d_flag > 1)
- debug_message("[%s(%d)]: %s", command_giver->name, length, buff);
- /*
- * Insert CR after all NL.
- */
- to = 0;
- for (from = 0; length-from >= min_length; to = 0 ) {
- for ( ; to < (sizeof buff2)-1 && buff[from] != '\0';) {
- if (buff[from] == '\n')
- buff2[to++] = '\r';
- buff2[to++] = buff[from++];
- }
- if ( to == sizeof(buff2) ) {
- to -= 2;
- from--;
- }
- chunk = to;
- /*
- * We split up the message into something smaller than the max size.
- */
- if (!command_giver->interactive->window) {
- if ((n = s_write(ip->socket, buff2, chunk)) == -1) {
- if (errno == EMSGSIZE) {
- fprintf(stderr, "comm1: write EMSGSIZE.\n");
- return;
- }
- if (errno == EINVAL) {
- fprintf(stderr, "comm1: write EINVAL.\n");
- if (old_message_length) remove_flush_entry(ip);
- ip->do_close = 1;
- return;
- }
- if (errno == ENETUNREACH) {
- fprintf(stderr, "comm1: write ENETUNREACH.\n");
- if (old_message_length) remove_flush_entry(ip);
- ip->do_close = 1;
- return;
- }
- if (errno == EHOSTUNREACH) {
- fprintf(stderr, "comm1: write EHOSTUNREACH.\n");
- if (old_message_length) remove_flush_entry(ip);
- ip->do_close = 1;
- return;
- }
- if (errno == EPIPE) {
- fprintf(stderr, "comm1: write EPIPE detected\n");
- if (old_message_length) remove_flush_entry(ip);
- ip->do_close = 1;
- return;
- }
- if (errno == EWOULDBLOCK) {
- fprintf(stderr, "comm1: write EWOULDBLOCK. Message discarded.\n");
- if (old_message_length) remove_flush_entry(ip);
- /* ip->do_close = 1; -- LA */
- return;
- }
- fprintf(stderr, "write: unknown errno %d\n", errno);
- perror("write");
- if (old_message_length) remove_flush_entry(ip);
- ip->do_close = 1;
- return;
- }
- if (n != chunk)
- fprintf(stderr, "write socket: wrote %d, should be %d.\n", n, chunk);
- } else {
- if ((n = DoWindowWrite(command_giver->interactive, buff2, chunk)) == -1) {
- fprintf(stderr, "comm1: write failed\n");
- if (old_message_length) remove_flush_entry(ip);
- ip->do_close = 1;
- return;
- }
- }
- }
- length -= from;
- ip->message_length=length;
- if (from) strncpy(ip->message_buf, buff+from, length);
- if (length && !old_message_length ) { /* buffer became 'dirty' */
- if (ip->next_player_for_flush = first_player_for_flush ) {
- first_player_for_flush->interactive->previous_player_for_flush =
- command_giver;
- }
- ip->previous_player_for_flush = 0;
- first_player_for_flush = command_giver;
- }
- if ( !length && old_message_length ) { /* buffer has become empty */
- remove_flush_entry(ip);
- }
- }
-
- void remove_flush_entry(struct interactive *ip)
- {
-
- ip->message_length=0;
- if (ip->previous_player_for_flush) {
- ip->previous_player_for_flush->interactive->next_player_for_flush
- = ip->next_player_for_flush;
- } else {
- first_player_for_flush = ip->next_player_for_flush;
- }
- if (ip->next_player_for_flush) {
- ip->next_player_for_flush->interactive->previous_player_for_flush
- = ip->previous_player_for_flush;
- }
- }
-
- void flush_all_player_mess() {
- struct object *p,*np;
- struct object *save = command_giver;
-
- for ( p = first_player_for_flush; p; p=np) {
- np = p->interactive->next_player_for_flush;
- /* beware of side-effects when calling add_message the first time! */
- command_giver = p;
- add_message(MESSAGE_FLUSH);
- }
- command_giver=save;
- }
-
-
- /*
- * Copy a string, replacing newlines with '\0'. Also add an extra
- * space and back space for every newline. This trick will allow
- * otherwise empty lines, as multiple newlines would be replaced by
- * multiple zeroes only.
- */
- static int copy_chars(from, to, n)
- char *from, *to;
- int n;
- {
- int i;
- char *start = to;
- for (i=0; i<n; i++) {
- if (from[i] == '\r')
- continue;
- if (from[i] == '\n') {
- *to++ = ' ';
- *to++ = '\b';
- *to++ = '\0';
- continue;
- }
- *to++ = from[i];
- }
- return to - start;
- }
-
-
- /*
- * Get a message from any player. For all players without a completed
- * cmd in their input buffer, read their socket. Then, return the first
- * cmd of the next player in sequence that has a complete cmd in their buffer.
- * CmdsGiven is used to allow people in ED to send more cmds (if they have
- * them queued up) than normal players. If we get a heartbeat, still read
- * all sockets; if the next cmd giver is -1, we have already cycled and
- * can go back to do the heart beat.
- */
-
- int get_message(char *buff, int size)
- {
- int c;
- char *p;
- int i, res;
- int length;
- int new_socket;
- struct timeval timeout;
- struct interactive *ip = 0;
- struct sockaddr_in addr;
- extern int game_is_being_shut_down;
-
- /*
- * Stay in this loop until we have a message from a player.
- */
- while(!game_is_being_shut_down) {
- LPEvents();
-
- /* First, try to get a new player... */
- if (MULTI_CONNECTION) {
- length = sizeof addr;
- new_socket = s_accept(s, (struct sockaddr *)&addr, &length);
- if (new_socket != -1) {
- new_player(new_socket, &addr, length);
- } else if (new_socket == -1 && errno != EWOULDBLOCK && errno != EINTR) {
- perror("accept");
- LPExit(1);
- }
- }
-
- nfds = 0;
- FD_ZERO(&readfds);
- for (i = 0; i < MAX_PLAYERS; i++) {
- if (!(ip = all_players[i]))
- continue;
- if (ip->do_close) {
- ip->do_close = 0;
- remove_interactive(ip->ob);
- continue;
- }
- if (!first_cmd_in_buf(ip)) {
- FD_SET(ip->socket, &readfds);
- if (ip->socket >= nfds)
- nfds = ip->socket+1;
- }
- }
-
- res = 0;
- if (MULTI_CONNECTION) {
- timeout.tv_sec = twait; /* avoid busy waiting when no buffered cmds */
- timeout.tv_usec = 0;
- res = s_select(nfds, &readfds, 0, 0, &timeout);
- }
- if (timer_expired()) {
- twait = 0;
- comm_time_to_call_heart_beat = 1;
- goto return_next_command;
- }
- if (res == -1) {
- twait = 0;
- if (errno == EINTR) /* if we got an alarm, finish the round */
- goto return_next_command;
- perror("select");
- return 0;
- }
- for (i = 0; i < MAX_PLAYERS; i++) { /* read all pending sockets */
- ip = all_players[i];
- if (ip == 0)
- continue;
- if (!ip->window) {
- if (res && FD_ISSET(ip->socket, &readfds)) { /* read this player */
- int l;
-
- /*
- * Don't overfill their buffer.
- * Use a very conservative estimate on how much we can
- * read.
- */
- l = (MAX_TEXT - ip->text_end - 1)/3;
- if (l < size) size = l;
-
- if ((l = s_read(ip->socket, buff, size)) == -1) {
- if (errno == ENETUNREACH) {
- debug_message("Net unreachable detected.\n");
- remove_interactive(ip->ob);
- continue;
- }
- if (errno == EHOSTUNREACH) {
- debug_message("Host unreachable detected.\n");
- remove_interactive(ip->ob);
- continue;
- }
- if (errno == ETIMEDOUT) {
- debug_message("Connection timed out detected.\n");
- remove_interactive(ip->ob);
- continue;
- }
- if (errno == ECONNRESET) {
- debug_message("Connection reset by peer detected.\n");
- remove_interactive(ip->ob);
- continue;
- }
- if (errno == EWOULDBLOCK) {
- debug_message("read would block socket %d!\n", ip->socket);
- remove_interactive(ip->ob);
- continue;
- }
- if (errno == EMSGSIZE) {
- debug_message("read EMSGSIZE !\n");
- continue;
- }
- perror("read");
- debug_message("Unknown errno %d\n", errno);
- remove_interactive(ip->ob);
- continue;
- }
- if (l == 0) {
- if (ip->closing)
- fatal("Tried to read from closing socket.\n");
- remove_interactive(ip->ob);
- return 0;
- }
- buff[l] = '\0';
- /* replace newlines by nulls and catenate to buffer */
- ip->text_end +=
- copy_chars(buff, ip->text + ip->text_end, l);
- /* now, text->end is just after the last char read. If last */
- /* char was a nl, char *before* text_end will be null. */
- ip->text[ip->text_end] = '\0';
- }
- } else {
- if ((c = DoWindowRead(ip)) != -1) {
- if (c == '\n') {
- ip->text[ip->text_end++] = '\0';
- } else if (c != '\r') {
- ip->text[ip->text_end++] = c;
- }
- ip->text[ip->text_end] = '\0';
- }
- }
- }
- /*
- * we have read the sockets; now find and return a command
- */
- return_next_command:
- twait = 0;
- ip = 0;
-
- for (i = 0; i < MAX_PLAYERS + 1; i++) {
- if (NextCmdGiver == -1) { /* we have cycled around all players */
- CmdsGiven = 0; /* check heart beat */
- IncCmdGiver;
- if (comm_time_to_call_heart_beat) {
- time_to_call_heart_beat = 1; /* twait stays 0! */
- return 0;
- }
- }
- ip = all_players[NextCmdGiver];
- if (ip && (p = first_cmd_in_buf(ip))) /* wont respond to partials */
- break;
- CmdsGiven = 0; /* new player, no cmds issued */
- IncCmdGiver;
- }
-
- if ((!ip) || !p) { /* no cmds found; loop and select (on timeout) again */
- if (comm_time_to_call_heart_beat) { /* may as well do it now */
- time_to_call_heart_beat = 1; /* no cmds, do heart beat */
- NextCmdGiver = StartCmdGiver;/* do a complete poll next time */
- CmdsGiven = 0;
- return(0);
- }
- /* no heart beat to do and no cmds pending - avoid busy wait on select */
- twait = 1;
- continue; /* else await another cmd */
- }
-
- /*
- * we have a player cmd - return it. If he is in ed, count his
- * cmds, else only allow 1 cmd. If he has only one partially
- * completed cmd left after * this, move it to the start of his
- * buffer; new stuff will be appended.
- */
-
- command_giver = ip->ob;
- telnet_neg(buff, p);
- next_cmd_in_buf(ip); /* move on buffer pointers */
-
- /* if he is not in ed, dont let him issue another till the poll comes again */
-
- if (ip->ed_buffer && CmdsGiven < ALLOWED_ED_CMDS) {
- CmdsGiven++;
- } else {
- IncCmdGiver;
- CmdsGiven = 0;
- }
-
- /*
- * Manage snooping - should the snooper see type ahead? Well, he doesn't here
- */
- if (ip->snoop_by && !ip->noecho) {
- command_giver = ip->snoop_by->ob;
- add_message("%% %s\n", buff);
- }
- command_giver = ip->ob;
-
- if (ip->noecho) {
- /* Must not enable echo before the user input is received. */
- add_message("%c%c%c", IAC, WONT, TELOPT_ECHO);
- }
- ip->noecho = 0;
- ip->last_time = current_time;
- return 1;
- }
- }
-
- /*
- * find the first character of the next complete cmd in a buffer, 0 if no
- * completed cmd. There is a completed cmd if there is a null between
- * text_start and text_end. Zero length commands are discarded (as occur
- * between <cr> and <lf>). Update text_start if we have to skip leading
- * nulls.
- */
-
- char * first_cmd_in_buf(struct interactive *ip)
- {
- char * p, *q;
-
- p = ip->text_start + ip->text;
- while ((p < (ip->text_end + ip->text)) && !*p) /* skip null input */
- p++;
-
- ip->text_start = p - ip->text;
-
- if (ip->text_start >= ip->text_end) {
- ip->text_start = ip->text_end = 0;
- ip->text[0] = '\0';
- return(0);
- }
-
- while ((p < (ip->text_end + ip->text)) && *p) /* find end of cmd */
- p++;
-
- if (p < ip->text + ip->text_end) /* null terminated, was command */
- return(ip->text + ip->text_start);
-
- /* have a partial command at end of buffer; move it to start, return null */
- /* if it can't move down, truncate it and return it as cmd. */
-
- p = ip->text + ip->text_start;
- q = ip->text;
- while (p < (ip->text + ip->text_end))
- *(q++) = *(p++);
-
- ip->text_end -= ip->text_start;
- ip->text_start = 0;
- if (ip->text_end > MAX_TEXT - 2) {
- ip->text[ip->text_end-2] = '\0'; /* nulls to truncate */
- ip->text[ip->text_end-1] = '\0'; /* nulls to truncate */
- ip->text_end--;
- return(ip->text);
- }
- /* buffer not full and no newline - no cmd. */
- return(0);
- }
-
- /*
- * move pointers to next cmd, or clear buf.
- */
-
- void next_cmd_in_buf(ip)
- struct interactive *ip;
- {
- char * p = ip->text + ip->text_start;
-
- while (*p && p < ip->text + ip->text_end)
- p++;
- /* skip past any nulls at the end */
- while (!*p && p < ip->text + ip->text_end)
- p++;
- if (p < ip->text + ip->text_end) {
- ip->text_start = p - ip->text;
- } else {
- ip->text_start = ip->text_end = 0;
- ip->text[0] = '\0';
- }
- }
-
- /*
- * Remove an interactive player immediately.
- */
- void remove_interactive(ob)
- struct object *ob;
- {
- int i;
- extern void save_ed_buffer();
- struct object *save = command_giver;
-
- for (i=0; i<MAX_PLAYERS; i++) {
- if (all_players[i] != ob->interactive)
- continue;
- if (ob->interactive->closing)
- fatal("Double call to remove_interactive()\n");
- ob->interactive->closing = 1;
- if (ob->interactive->snoop_by) {
- ob->interactive->snoop_by->snoop_on = 0;
- ob->interactive->snoop_by = 0;
- }
- if (ob->interactive->snoop_on) {
- ob->interactive->snoop_on->snoop_by = 0;
- ob->interactive->snoop_on = 0;
- }
- command_giver = ob;
- add_message("Closing down.\n");
- if (ob->interactive->ed_buffer) {
- save_ed_buffer();
- }
- add_message(MESSAGE_FLUSH);
- num_player--;
- if (ob->interactive->input_to) {
- free_object(ob->interactive->input_to->ob, "remove_interactive");
- free_sentence(ob->interactive->input_to);
- ob->interactive->input_to = 0;
- }
- if (!ob->interactive->window) {
- s_shutdown(ob->interactive->socket, 2);
- s_close(ob->interactive->socket);
- #ifdef ACCESS_RESTRICTED
- release_host_access(ob->interactive->access_class);
- #endif
- } else {
- DoDisposeWindow(ob->interactive->window);
- }
- xfree((char *)ob->interactive);
- ob->interactive = 0;
- all_players[i] = 0;
- free_object(ob, "remove_interactive");
- command_giver = save;
- return;
- }
- (void)fprintf(stderr, "Could not find and remove player %s\n", ob->name);
- abort();
- }
-
- /*
- * get the I'th player object from the interactive list, i starts at 0
- * and can go to num_player - 1. For users(), etc.
- */
- struct object *get_interactive_object(int i)
- {
- int n;
-
- if (i >= num_player) /* love them ASSERTS() :-) */
- fatal("Get interactive (%d) with only %d players!", i, num_player);
-
- for (n = 0; n < MAX_PLAYERS; n++)
- if (all_players[n])
- if (!(i--))
- return(all_players[n]->ob);
-
- fatal("Get interactive: player %d not found! (num_players = %d)",
- i, num_player);
- return 0; /* Just to satisfy some compiler warnings */
- }
-
- void new_player(int new_socket, struct sockaddr_in *addr, int len)
- {
- int i;
- char *p;
- void *class;
-
- if (new_socket) {
- #ifdef ACCESS_RESTRICTED
- if (!(class = allow_host_access(new_socket, new_socket)))
- return;
- #endif
- if (d_flag > 1) debug_message("New player at socket %d.\n", new_socket);
- } else {
- if (d_flag > 1) debug_message("New player from console.\n");
- }
- for (i=0; i<MAX_PLAYERS; i++) {
- struct object *ob;
- struct svalue *ret;
- extern struct object *master_ob;
-
- if (all_players[i] != 0)
- continue;
- assert_master_ob_loaded();
- command_giver = master_ob;
- master_ob->interactive =
- (struct interactive *)xalloc(sizeof (struct interactive));
- master_ob->interactive->default_err_message = 0;
- master_ob->flags |= O_ONCE_INTERACTIVE;
- /* This initialization is not pretty. */
- master_ob->interactive->ob = master_ob;
- master_ob->interactive->text[0] = '\0';
- master_ob->interactive->input_to = 0;
- master_ob->interactive->closing = 0;
- master_ob->interactive->snoop_on = 0;
- master_ob->interactive->snoop_by = 0;
- master_ob->interactive->text_end = 0;
- master_ob->interactive->text_start = 0;
- master_ob->interactive->do_close = 0;
- master_ob->interactive->noecho = 0;
- master_ob->interactive->trace_level = 0;
- master_ob->interactive->trace_prefix = 0;
- master_ob->interactive->last_time = current_time;
- master_ob->interactive->ed_buffer = 0;
- master_ob->interactive->message_length=0;
- master_ob->interactive->window = 0;
- master_ob->interactive->socket = 0;
- all_players[i] = master_ob->interactive;
- set_prompt("> ");
-
- if (new_socket) {
- all_players[i]->socket = new_socket;
- memcpy((char *)&all_players[i]->addr, (char *)addr, len);
- #ifdef ACCESS_RESTRICTED
- all_players[i]->access_class = class;
- #endif
- } else {
- master_ob->interactive->window = DoGetWindow(master_ob->interactive);
- if (!master_ob->interactive->window) {
- remove_interactive(master_ob);
- return;
- }
- }
- num_player++;
- /*
- * The player object has one extra reference.
- * It is asserted that the master_ob is loaded.
- */
- add_ref(master_ob, "new_player");
- ret = apply_master_ob("connect", 0);
- if (ret == 0 || ret->type != T_OBJECT) {
- remove_interactive(master_ob);
- return;
- }
- /*
- * There was an object returned from connect(). Use this as the
- * player object.
- */
- ob = ret->u.ob;
- ob->interactive = master_ob->interactive;
- ob->interactive->ob = ob;
- ob->flags |= O_ONCE_INTERACTIVE;
- master_ob->flags &= ~O_ONCE_INTERACTIVE;
- add_message(MESSAGE_FLUSH);
- master_ob->interactive = 0;
- free_object(master_ob, "reconnect");
- add_ref(ob, "new_player");
- command_giver = ob;
- logon(ob);
- flush_all_player_mess();
- return;
- }
- if (new_socket) {
- p = "Lpmud is full. Come back later.\r\n";
- s_write(new_socket, p, strlen(p));
- s_close(new_socket);
- } else {
- }
- }
-
- int call_function_interactive(struct interactive *i, char *str)
- {
- char *function;
- struct object *ob;
-
- if (!i->input_to)
- return 0;
- /*
- * Special feature: input_to() has been called to setup
- * a call to a function.
- */
- if (i->input_to->ob->flags & O_DESTRUCTED) {
- /* Sorry, the object has selfdestructed ! */
- free_object(i->input_to->ob, "call_function_interactive");
- free_sentence(i->input_to);
- i->input_to = 0;
- return 0;
- }
- free_object(i->input_to->ob, "call_function_interactive");
- function = string_copy(command_giver->interactive->input_to->function);
- ob = i->input_to->ob;
- free_sentence(i->input_to);
- /*
- * We must clear this reference before the call to apply(), because
- * someone might want to set up a new input_to().
- */
- i->input_to = 0;
- /*
- * Now we set current_object to this object, so that input_to will
- * work for static functions.
- */
- push_constant_string(str);
- current_object = ob;
- (void)apply(function, ob, 1);
- xfree(function);
- flush_all_player_mess();
- return 1;
- }
-
- int set_call(struct object *ob, struct sentence *sent, int noecho)
- {
- struct object *save = command_giver;
- if (ob == 0 || sent == 0)
- return 0;
- if (ob->interactive == 0 || ob->interactive->input_to)
- return 0;
- ob->interactive->input_to = sent;
- ob->interactive->noecho = noecho;
- command_giver = ob;
- if (noecho)
- add_message("%c%c%c", IAC, WILL, TELOPT_ECHO);
- command_giver = save;
- return 1;
- }
-
- void show_info_about(char *str, char *room, struct interactive *i)
- {
- add_message("%-15s %s\n", str, room);
- }
-
- void remove_all_players()
- {
- int i;
- extern jmp_buf error_recovery_context;
- extern int error_recovery_context_exists;
-
- for (i=0; i<MAX_PLAYERS; i++) {
- if (all_players[i] == 0)
- continue;
- command_giver = all_players[i]->ob;
- error_recovery_context_exists = 2;
- push_pop_error_context(1);
- if (!setjmp(error_recovery_context)) {
- (void)apply("quit", all_players[i]->ob, 0);
- } else {
- push_pop_error_context(-1);
- }
- }
- }
-
- void set_prompt(char *str)
- {
- command_giver->interactive->prompt = str;
- }
-
- /*
- * Print the prompt, but only if input_to not is disabled.
- */
- void print_prompt()
- {
- if (command_giver == 0)
- fatal("command_giver == 0.\n");
- if (command_giver->interactive->input_to == 0) {
- add_message(command_giver->interactive->prompt);
- if (1) { /* add test for heart_beat later */
- flush_all_player_mess();
- }
- }
- }
-
- /*
- * Let object 'me' snoop object 'you'. If 'you' is 0, then turn off
- * snooping.
- */
- void set_snoop(struct object *me, struct object *you)
- {
- int i;
- struct interactive *on = 0, *by = 0, *tmp;
-
- if (me->flags & O_DESTRUCTED)
- return;
- if (you && (you->flags & O_DESTRUCTED))
- return;
- for(i=0; i<MAX_PLAYERS && (on == 0 || by == 0); i++) {
- if (all_players[i] == 0)
- continue;
- if (all_players[i]->ob == me)
- by = all_players[i];
- else if (all_players[i]->ob == you)
- on = all_players[i];
- }
- if (you == 0) {
- if (by == 0)
- error("Could not find myself to stop snoop.\n");
- add_message("Ok.\n");
- if (by->snoop_on == 0)
- return;
- by->snoop_on->snoop_by = 0;
- by->snoop_on = 0;
- return;
- }
- if (on == 0 || by == 0) {
- add_message("Failed.\n");
- return;
- }
- if (by->snoop_on) {
- by->snoop_on->snoop_by = 0;
- by->snoop_on = 0;
- }
- if (on->snoop_by) {
- add_message("Busy.\n");
- return;
- }
- /*
- * Protect against snooping loops.
- */
- for (tmp = on; tmp; tmp = tmp->snoop_on) {
- if (tmp == by) {
- add_message("Busy.\n");
- return;
- }
- }
- on->snoop_by = by;
- by->snoop_on = on;
- add_message("Ok.\n");
- return;
- }
-
- /*
- * Let object 'me' snoop object 'you'. If 'you' is 0, then turn off
- * snooping.
- *
- * This routine is almost identical to the old set_snoop. The main
- * difference is that the routine writes nothing to player directly,
- * all such communication is taken care of by the mudlib. It communicates
- * with master.c in order to find out if the operation is permissble or
- * not. The old routine let everyone snoop anyone. This routine also returns
- * 0 or 1 depending on success.
- */
- int new_set_snoop(struct object *me, struct object *you)
- {
- int i;
- struct svalue *ret;
- struct interactive *on = 0, *by = 0, *tmp;
-
- /* Stop if people managed to quit before we got this far */
- if (me->flags & O_DESTRUCTED)
- return 0;
- if (you && (you->flags & O_DESTRUCTED))
- return 0;
-
- /* Find the snooper & snopee */
- for(i = 0 ; i < MAX_PLAYERS && (on == 0 || by == 0); i++) {
- if (all_players[i] == 0)
- continue;
- if (all_players[i]->ob == me)
- by = all_players[i];
- else if (all_players[i]->ob == you)
- on = all_players[i];
- }
-
- /* Illegal snoop attempt by null object */
- if (!current_object->eff_user)
- return 0;
-
- /* Check for permissions with valid_snoop in master */
- push_object(me);
- if (you == 0) {
- push_number(0);
- } else {
- push_object(you);
- }
- ret = apply_master_ob("valid_snoop", 2);
-
- if (!ret || ret->type != T_NUMBER || ret->u.number == 0)
- return 0;
-
- /* Stop snoop */
- if (you == 0) {
- if (by == 0)
- error("Could not find snooper to stop snoop on.\n");
- if (by->snoop_on == 0)
- return 1;
- by->snoop_on->snoop_by = 0;
- by->snoop_on = 0;
- return 1;
- }
-
- /* Strange event, but possible, so test for it */
- if (on == 0 || by == 0)
- return 0;
-
- /* Protect against snooping loops */
- for (tmp = on; tmp; tmp = tmp->snoop_on) {
- if (tmp == by)
- return 0;
- }
-
- /* Terminate previous snoop, if any */
- if (by->snoop_on) {
- by->snoop_on->snoop_by = 0;
- by->snoop_on = 0;
- }
- if (on->snoop_by) {
- on->snoop_by->snoop_on = 0;
- on->snoop_by = 0;
- }
- on->snoop_by = by;
- by->snoop_on = on;
- return 1;
-
- }
-
- #define TS_DATA 0
- #define TS_IAC 1
- #define TS_WILL 2
- #define TS_WONT 3
- #define TS_DO 4
- #define TS_DONT 5
-
- void telnet_neg(char *to, char *from)
- {
- int ch;
- int state = TS_DATA;
- char *first = to;
-
- while(1) {
- ch = (*from++ & 0xff);
- switch(state) {
- case TS_DATA:
- switch(ch) {
- case IAC:
- state = TS_IAC;
- continue;
- case '\b': /* Backspace */
- case 0x7f: /* Delete */
- if (to <= first)
- continue;
- to -= 1;
- continue;
- default:
- if (ch & 0x80) {
- if (d_flag) debug_message("Tel_neg: 0x%x\n", ch);
- continue;
- }
- *to++ = ch;
- if (ch == 0)
- return;
- continue;
- }
- case TS_IAC:
- switch(ch) {
- case WILL:
- state = TS_WILL;
- continue;
- case WONT:
- state = TS_WONT;
- continue;
- case DO:
- state = TS_DO;
- continue;
- case DONT:
- state = TS_DONT;
- continue;
- case DM:
- break;
- case NOP:
- case GA:
- default:
- break;
- }
- state = TS_DATA;
- continue;
- case TS_WILL:
- if (d_flag) debug_message("Will %s\n", telopts[ch]);
- state = TS_DATA;
- continue;
- case TS_WONT:
- if (d_flag) debug_message("Wont %s\n", telopts[ch]);
- state = TS_DATA;
- continue;
- case TS_DO:
- if (d_flag) debug_message("Do %s\n", telopts[ch]);
- state = TS_DATA;
- continue;
- case TS_DONT:
- if (d_flag) debug_message("Dont %s\n", telopts[ch]);
- state = TS_DATA;
- continue;
- default:
- if (d_flag) debug_message("Bad state: 0x%x\n", state);
- state = TS_DATA;
- continue;
- }
- }
- }
-
- #define IPSIZE 200
- static struct ipentry {
- long addr;
- char *name;
- } iptable[IPSIZE];
- static int ipcur;
-
- char *query_ip_name(struct object *ob)
- {
- int i;
-
- if (ob == 0)
- ob = command_giver;
- if (!ob || ob->interactive == 0)
- return 0;
- if (!ob->interactive->window) {
- for(i = 0; i < IPSIZE; i++) {
- if (iptable[i].addr == ob->interactive->addr.sin_addr.s_addr && iptable[i].name)
- return iptable[i].name;
- }
- return inet_ntoa(ob->interactive->addr.sin_addr);
- } else {
- return MUDHOSTNAME;
- }
- }
-
- static void add_ip_entry(long addr, char *name)
- {
- int i;
-
- for(i = 0; i < IPSIZE; i++) {
- if (iptable[i].addr == addr)
- return;
- }
- iptable[ipcur].addr = addr;
- if (iptable[ipcur].name)
- free_string(iptable[ipcur].name);
- iptable[ipcur].name = make_shared_string(name);
- ipcur = (ipcur+1) % IPSIZE;
- }
-
- static char ipnum[] = "1.1.1.1";
-
- char *query_ip_number(struct object *ob)
- {
- if (ob == 0)
- ob = command_giver;
- if (!ob || ob->interactive == 0)
- return 0;
- if (!ob->interactive->window) {
- return inet_ntoa(ob->interactive->addr.sin_addr);
- } else {
- return ipnum;
- }
- }
-
- char *query_host_name() {
- static char name[100];
-
- if (MULTI_CONNECTION) {
- gethostname(name, sizeof name);
- name[sizeof name - 1] = '\0'; /* Just to make sure */
- return name;
- }
- return MUDHOSTNAME;
- }
-
- struct object *query_snoop(ob)
- struct object *ob;
- {
- if (ob->interactive->snoop_by == 0)
- return 0;
- return ob->interactive->snoop_by->ob;
- }
-
- int query_idle(ob)
- struct object *ob;
- {
- if (!ob->interactive)
- error("query_idle() of non-interactive object.\n");
- return current_time - ob->interactive->last_time;
- }
-
- void notify_no_command() {
- char *p,*m;
-
- if (!command_giver->interactive)
- return;
- p = command_giver->interactive->default_err_message;
- if (p) {
- m = process_string(p); /* We want 'value by function call' /JnA */
- if (!shadow_catch_message(command_giver, m))
- add_message(m);
- if (m != p)
- xfree(m);
- free_string(p);
- command_giver->interactive->default_err_message = 0;
- } else {
- add_message(WHAT_MESSAGE);
- }
- }
-
- void clear_notify() {
- if (!command_giver->interactive)
- return;
- if (command_giver->interactive->default_err_message) {
- free_string(command_giver->interactive->default_err_message);
- command_giver->interactive->default_err_message = 0;
- }
- }
-
- void set_notify_fail_message(str)
- char *str;
- {
- if (!command_giver || !command_giver->interactive)
- return;
- clear_notify();
- if (command_giver->interactive->default_err_message)
- free_string(command_giver->interactive->default_err_message);
- command_giver->interactive->default_err_message = make_shared_string(str);
- }
-
- int replace_interactive(ob, obfrom, /*IGN*/name)
- struct object *ob;
- struct object *obfrom;
- char *name;
- {
- /* marion
- * i see no reason why to restrict this, besides - the length
- * (was) missing to strncmp()
- * JnA: There is every reason to restrict this.
- * Otherwise I can write my own player object without any security
- * at all!
- */
- struct svalue *v;
-
- push_string(name, STRING_CONSTANT);
- v = apply_master_ob("valid_exec", 1);
- if (!v || v->type != T_NUMBER || v->u.number == 0)
- return 0;
- /* fprintf(stderr,"DEBUG: %s,%s\n",ob->name,obfrom->name); */
- if (ob->interactive)
- error("Bad argument1 to exec()\n");
- if (!obfrom->interactive)
- error("Bad argument2 to exec()\n");
- if (obfrom->interactive->message_length) {
- struct object *save;
- save=command_giver;
- command_giver=obfrom;
- add_message(MESSAGE_FLUSH);
- command_giver=save;
- }
- ob->interactive = obfrom->interactive;
- obfrom->interactive = 0;
- ob->interactive->ob = ob;
- ob->flags |= O_ONCE_INTERACTIVE;
- obfrom->flags &= ~O_ONCE_INTERACTIVE;
- add_ref(ob, "exec");
- free_object(obfrom, "exec");
- if (obfrom == command_giver) command_giver = ob;
- return 1;
- }
-
- #ifdef DEBUG
- /*
- * This is used for debugging reference counts.
- */
-
- void update_ref_counts_for_players() {
- int i;
-
- for (i=0; i<MAX_PLAYERS; i++) {
- if (all_players[i] == 0)
- continue;
- all_players[i]->ob->extra_ref++;
- if (all_players[i]->input_to)
- all_players[i]->input_to->ob->extra_ref++;
- }
- }
- #endif /* DEBUG */
-